package com.broada.apm.indicator.api.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation.SingleValue;
import org.elasticsearch.search.aggregations.metrics.stats.extended.ExtendedStats;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.es.indices.support.PerfIndicesBuilder;
import com.broada.apm.indicator.api.PerformanceQueryService;
import com.broada.apm.indicator.api.common.ApmDataIndicatorException;
import com.broada.apm.indicator.api.model.SearchCondition;
import com.broada.apm.indicator.api.model.SearchConditionComparator;
import com.broada.apm.indicator.api.model.SearchConditionItem;
import com.broada.apm.indicator.api.util.AggregationUtil;
import com.broada.apm.model.BaseResource.RESOURCE_TYPE;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.PerformanceView;
import com.broada.apm.model.Scope;
import com.broada.apm.utils.EsClientUtil;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.JsonUtil;

/*
 *   2015-4-15 jialin parseIndices()函数调整，更易读
 *
 * */
public class EsQueryPerformanceServiceImpl implements PerformanceQueryService {
	Logger log = LoggerFactory.getLogger(EsQueryPerformanceServiceImpl.class);
	private Client client = EsClientUtil.getTransportClient();
	
	private static final String APP_DEFAULT = "default";

	@Override
	public PagingList<PerformanceView> queryPerf(SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("性能查询失败,条件参数timestamp不存在");
		PagingList<PerformanceView> result = new PagingList<PerformanceView>();
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices( (long)item.getValue(),
					(long) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APM_PINPOINT_SPAN.getType()).setPostFilter(queryBuilder)
					.setFrom(searchCondition.getStartRecord()).setSize(searchCondition.getPageSize());
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response != null && response.getHits().getHits().length > 0) {
				int pageSize = searchCondition.getPageSize();
				int pageIndex = searchCondition.getPageIndex();
				Long total = response.getHits().getTotalHits();
				pagingHandler(pageIndex, pageSize, total, result); // 处理分页
				for (SearchHit hit : response.getHits()) {
					String source = hit.sourceAsString();

					result.getData().add(new PerformanceView(JsonUtil.json2map(source)));
				}
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	public List<PerformanceView> queryAggregationTermsPerf(String applicationId, RESOURCE_TYPE type,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			String indices[] = parseIndices(applicationId, type, null, (Date) item.getValue(),
						(Date) item.getValue_End());
			String indextype = Scope.APMRUNNING_PERFS.getType();
			if (StringUtils.isNotBlank(applicationId)) {
				searchCondition.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
			}
			return queryAggregationTermsPerf(applicationId, indices, indextype, searchCondition);
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
	}
	
	public List<PerformanceView> queryAggregationTermsPerf(String applicationId, String[] indices, String indextype,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();

		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndicesOptions(IndicesOptions.lenientExpandOpen());
			searchBuilder.setSize(100);
			
			searchBuilder.setIndices(indices).setTypes(indextype).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}
	
	public List<PerformanceView> queryAggregationHistogramPerf(String applicationId, RESOURCE_TYPE type,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");

		try {
			searchCondition.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices(applicationId, type, null, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_PERFS.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	public List<PerformanceView> queryAggregationDateHistogramPerf(String applicationId, 
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");

		try {
			searchCondition.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
		
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			
			String indices[] = parseIndices( (long) item.getValue(),
					(long) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;
			SearchRequestBuilder searchBuilder = client.prepareSearch();
			
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APM_PINPOINT_SPAN.getType()).setQuery(queryBuilder);
			
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseDateHistogramAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public PerformanceView queryAggregationSingelePerfByDimensionType(String applicationId,  SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices( (long) item.getValue(),
					(long) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return null;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APM_PINPOINT_SPAN.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			Map<String, Object> agg = AggregationUtil.parseSingleAggregation(response.getAggregations());
			return new PerformanceView(agg);
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
	}

	/**
	 * 除了application维度根据索引划分，其他资源类型都存在同一索引下
	 * 
	 * @param applicationId
	 * @param type
	 * @param dimensionType
	 * @param start
	 * @param end
	 * @return
	 * @throws Exception
	 */
	private String[] parseIndices(String applicationId, RESOURCE_TYPE type, String dimensionType, Date start, Date end)
			throws Exception {
		PerfIndicesBuilder perfIncidesBuilder = PerfIndicesBuilder.getInstance();
		String param[] = null;
		String format = null;
		if (RESOURCE_TYPE.APPLICATION.equals(type)) {
			if (dimensionType == null) {
				param = new String[] {};
				format = perfIncidesBuilder.APM_PERF_Y_M;
			} else {
				param = new String[] { applicationId, dimensionType };
				format = perfIncidesBuilder.APM_PERF_A_D_Y_M;
			}
		} else if (RESOURCE_TYPE.SERVICE.equals(type)) {
			param = new String[] { applicationId };
			format = perfIncidesBuilder.APM_PERF_A_Y_M;
		} else if (RESOURCE_TYPE.RESOURCE.equals(type)) {
			param = new String[] { applicationId };
			format = perfIncidesBuilder.APM_PERF_A_R_Y_M;
		} else if (RESOURCE_TYPE.DOMAIN.equals(type)) {
			param = new String[] { applicationId };
			format = perfIncidesBuilder.APM_PERF_A_VY_Y_M;
		} else if (RESOURCE_TYPE.KEY_RESOURCE.equals(type)) {
			param = new String[] { applicationId };
			format = perfIncidesBuilder.APM_PERF_A_K_Y_M;
		}
		return perfIncidesBuilder.getPerfIndices(format, param, start, end);
	}

	/**
	 * 处理分页
	 * 
	 * @param pageIndex
	 * @param pageSize
	 * @param total
	 * @param result
	 */
	private void pagingHandler(int pageIndex, int pageSize, Long total, PagingList<PerformanceView> result) {
		int totalPage = 0;
		int number = total.intValue() % pageSize;
		if (number > 0) {
			totalPage = total.intValue() / pageSize + 1;
		} else {
			totalPage = total.intValue() / pageSize;
		}
		result.setTotalPages(totalPage);
		result.setStartPage(pageIndex);
		result.setTotalRecords(total);
		result.setPageSize(pageSize);
	}

	@Override
	public List<Map<String, Object>> queryErrorCodeCount(SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<Map<String, Object>> result = null;
		SearchConditionItem item = searchCondition.getConditionItem("startTime");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices ((long) item.getValue(),
					(long) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return new ArrayList<Map<String, Object>>();

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APM_PINPOINT_SPAN.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			result = AggregationUtil.parseTermsAggregations(response.getAggregations());

		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public Map<String, Object> queryAggregationPerfForThreshold(String applicationId, RESOURCE_TYPE type,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		Map<String, Object> result = new HashMap<String, Object>();
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");

		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices(applicationId, type, null, (Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_PERFS.getType()).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response.getHits().totalHits() <= 0) {
				return result;
			}
			
			boolean rttFlag = true;
			boolean rpmFlag = true;
			boolean apdexFlag = true;
			boolean errorFlag = true;
			boolean successFlag = true;
			boolean brttFlag = true;
			boolean brpmFlag = true;
			boolean bapdexFlag = true;
			boolean berrorFlag = true;
			boolean bsuccessFlag = true;
			for (SearchHit hit : response.getHits()) {
				String source = hit.sourceAsString();
				Map<String, Object> map = JsonUtil.json2map(source);
				if (!map.containsKey("system/throughput/total")) {
					rpmFlag = false;
				}
				if (!map.containsKey("system/score/apdex")) {
					apdexFlag = false;
				}
				if (!map.containsKey("system/response_time/avg")) {
					rttFlag = false;
				}
				if (!map.containsKey("system/error/count")) {
					errorFlag = false;
				}
				if (!map.containsKey("system/success/rate")) {
					successFlag = false;
				}
				if (!map.containsKey("business/throughput/total")) {
					brpmFlag = false;
				}
				if (!map.containsKey("business/score/apdex")) {
					bapdexFlag = false;
				}
				if (!map.containsKey("business/response_time/avg")) {
					brttFlag = false;
				}
				if (!map.containsKey("business/error/count")) {
					berrorFlag = false;
				}
				if (!map.containsKey("business/success/rate")) {
					bsuccessFlag = false;
				}
			}
			
//			StatisticalFacetBuilder rpm = FacetBuilders.statisticalFacet("system/throughput/total").field("system/throughput/total");
//			StatisticalFacetBuilder apdex = FacetBuilders.statisticalFacet("system/score/apdex").field("system/score/apdex");
//			StatisticalFacetBuilder rtt = FacetBuilders.statisticalFacet("system/response_time/avg").field("system/response_time/avg");
//			StatisticalFacetBuilder error = FacetBuilders.statisticalFacet("system/error/count").field("system/error/count");
//			StatisticalFacetBuilder success = FacetBuilders.statisticalFacet("system/success/rate").field("system/success/rate");
//			
//			StatisticalFacetBuilder brpm = FacetBuilders.statisticalFacet("business/throughput/total").field("business/throughput/total");
//			StatisticalFacetBuilder bapdex = FacetBuilders.statisticalFacet("business/score/apdex").field("business/score/apdex");
//			StatisticalFacetBuilder brtt = FacetBuilders.statisticalFacet("business/response_time/avg").field("business/response_time/avg");
//			StatisticalFacetBuilder berror = FacetBuilders.statisticalFacet("business/error/count").field("business/error/count");
//			StatisticalFacetBuilder bsuccess = FacetBuilders.statisticalFacet("business/success/rate").field("business/success/rate");
//			
//			response = searchBuilder.addFacet(rtt).addFacet(apdex).addFacet(rpm).addFacet(success).addFacet(error)
//					.addFacet(brtt).addFacet(bapdex).addFacet(brpm).addFacet(bsuccess).addFacet(berror)
//					.execute().actionGet();
			
			if (rpmFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("system/throughput/total_avg").field("system/throughput/total"))
				.addAggregation(AggregationBuilders.count("system/throughput/total_count").field("system/throughput/total"))
				.addAggregation(AggregationBuilders.extendedStats("system/throughput/total_ex").field("system/throughput/total"));
			}
			if (apdexFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("system/score/apdex_avg").field("system/score/apdex"))
				.addAggregation(AggregationBuilders.count("system/score/apdex_count").field("system/score/apdex"))
				.addAggregation(AggregationBuilders.extendedStats("system/score/apdex_ex").field("system/score/apdex"));
			}
			if (rttFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("system/response_time/avg_avg").field("system/response_time/avg"))
				.addAggregation(AggregationBuilders.count("system/response_time/avg_count").field("system/response_time/avg"))
				.addAggregation(AggregationBuilders.extendedStats("system/response_time/avg_ex").field("system/response_time/avg"));
			}
			if (errorFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("system/error/count_avg").field("system/error/count"))
				.addAggregation(AggregationBuilders.count("system/error/count_count").field("system/error/count"))
				.addAggregation(AggregationBuilders.extendedStats("system/error/count_ex").field("system/error/count"));
			}
			if (successFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("system/success/rate_avg").field("system/success/rate"))
				.addAggregation(AggregationBuilders.count("system/success/rate_count").field("system/success/rate"))
				.addAggregation(AggregationBuilders.extendedStats("system/success/rate_ex").field("system/success/rate"));
			}
			
			if (brpmFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("business/throughput/total_avg").field("business/throughput/total"))
				.addAggregation(AggregationBuilders.count("business/throughput/total_count").field("business/throughput/total"))
				.addAggregation(AggregationBuilders.extendedStats("business/throughput/total_ex").field("business/throughput/total"));
			}
			if (bapdexFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("business/score/apdex_avg").field("business/score/apdex"))
				.addAggregation(AggregationBuilders.count("business/score/apdex_count").field("business/score/apdex"))
				.addAggregation(AggregationBuilders.extendedStats("business/score/apdex_ex").field("business/score/apdex"));
			}
			if (brttFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("business/response_time/avg_avg").field("business/response_time/avg"))
				.addAggregation(AggregationBuilders.count("business/response_time/avg_count").field("business/response_time/avg"))
				.addAggregation(AggregationBuilders.extendedStats("business/response_time/avg_ex").field("business/response_time/avg"));
			}
			if (berrorFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("business/error/count_avg").field("business/error/count"))
				.addAggregation(AggregationBuilders.count("business/error/count_count").field("business/error/count"))
				.addAggregation(AggregationBuilders.extendedStats("business/error/count_ex").field("business/error/count"));
			}
			if (bsuccessFlag) {
				searchBuilder.addAggregation(AggregationBuilders.avg("business/success/rate_avg").field("business/success/rate"))
				.addAggregation(AggregationBuilders.count("business/success/rate_count").field("business/success/rate"))
				.addAggregation(AggregationBuilders.extendedStats("business/success/rate_ex").field("business/success/rate"));
			}
			response = searchBuilder.execute().actionGet();
			
			if (response.getAggregations() == null) {
				return result;
			}
			
			Aggregations aggregations = null;
			if (rttFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("system/throughput/total_avg");
				ValueCount count = aggregations.get("system/throughput/total_count");
				ExtendedStats extendedStats = aggregations.get("system/throughput/total_ex");
				result.put("rttAvg", avg.value());// 平均值
				result.put("rttSd", extendedStats.getStdDeviation());// Standard Deviation 标准差
				result.put("rttCount", count.getValue());// 个数
			}
			
			if (rpmFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("system/throughput/total_avg");
				ValueCount count = aggregations.get("system/throughput/total_count");
				ExtendedStats extendedStats = aggregations.get("system/throughput/total_ex");
				result.put("rpmAvg", avg.value());
				result.put("rpmSd",  extendedStats.getStdDeviation());
				result.put("rpmCount", count.getValue());
			}
			
			if (errorFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("system/error/count_avg");
				ValueCount count = aggregations.get("system/error/count_count");
				ExtendedStats extendedStats = aggregations.get("system/error/count_ex");
				result.put("errorAvg", avg.value());
				result.put("errorSd", extendedStats.getStdDeviation());
				result.put("errorCount", count.getValue());
			}
			
			if (successFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("system/success/rate_avg");
				ValueCount count = aggregations.get("system/success/rate_count");
				ExtendedStats extendedStats = aggregations.get("system/success/rate_ex");
				result.put("successAvg", avg.value());
				result.put("successSd", extendedStats.getStdDeviation());
				result.put("successCount", count.getValue());
			}

			if (apdexFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("system/score/apdex_avg");
				ValueCount count = aggregations.get("system/score/apdex_count");
				ExtendedStats extendedStats = aggregations.get("system/score/apdex_ex");
				result.put("apdexAvg", avg.value());
				result.put("apdexSd", extendedStats.getStdDeviation());
				result.put("apdexCount", count.getValue());
			}
			
			if (brttFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("business/response_time/avg_avg");
				ValueCount count = aggregations.get("business/response_time/avg_count");
				ExtendedStats extendedStats = aggregations.get("business/response_time/avg_ex");
				result.put("brttAvg", avg.value());// 平均值
				result.put("brttSd", extendedStats.getStdDeviation());// Standard Deviation 标准差
				result.put("brttCount", count.getValue());// 个数
			}
			
			if (brpmFlag) {
				aggregations = (Aggregations) response.getAggregations().asMap().get("business/throughput/total");
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("business/throughput/total_avg");
				ValueCount count = aggregations.get("business/throughput/total_count");
				ExtendedStats extendedStats = aggregations.get("business/throughput/total_ex");
				result.put("brpmAvg", avg.value());
				result.put("brpmSd", extendedStats.getStdDeviation());
				result.put("brpmCount", count.getValue());
			}
			
			if (berrorFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("business/error/count_avg");
				ValueCount count = aggregations.get("business/error/count_count");
				ExtendedStats extendedStats = aggregations.get("business/error/count_ex");
				result.put("berrorAvg", avg.value());
				result.put("berrorSd", extendedStats.getStdDeviation());
				result.put("berrorCount", count.getValue());
			}
			
			if (bsuccessFlag) {
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("business/success/rate_avg");
				ValueCount count = aggregations.get("business/success/rate_count");
				ExtendedStats extendedStats = aggregations.get("business/success/rate_ex");
				result.put("bsuccessAvg", avg.value());
				result.put("bsuccessSd",  extendedStats.getStdDeviation());
				result.put("bsuccessCount", count.getValue());
			}

			if (bapdexFlag) {
				aggregations = (Aggregations) response.getAggregations().asMap().get("business/score/apdex");
				aggregations = (Aggregations) response.getAggregations();
				SingleValue avg = aggregations.get("business/score/apdex_avg");
				ValueCount count = aggregations.get("business/score/apdex_count");
				ExtendedStats extendedStats = aggregations.get("business/score/apdex_ex");
				result.put("bapdexAvg", avg.value());
				result.put("bapdexSd",  extendedStats.getStdDeviation());
				result.put("bapdexCount", count.getValue());
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "获取性能数据出错", e);
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public PagingList<PerformanceView> queryTransactions(SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("startTime");
		
		if (item == null)
			throw new IllegalArgumentException("交易跟踪查询失败,条件参数startTime不存在");
		PagingList<PerformanceView> result = new PagingList<PerformanceView>();
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getTransactionIndices((Date) item.getValue(),
					(Date) item.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

//			String indices[] = {"apm_trade_detail_y2016_m7_d7"};
			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APMRUNNING_TRANS.getType()).setPostFilter(queryBuilder)
					.setFrom(searchCondition.getStartRecord()).setSize(searchCondition.getPageSize());
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response.getHits() != null && response.getHits().getHits().length > 0) {
				int pageSize = searchCondition.getPageSize();
				int pageIndex = searchCondition.getPageIndex();
				Long total = response.getHits().getTotalHits();
				pagingHandler(pageIndex, pageSize, total, result); // 处理分页
				for (SearchHit hit : response.getHits()) {
					String source = hit.sourceAsString();

					result.getData().add(new PerformanceView(JsonUtil.json2map(source)));
				}
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}
	
	@Override
	public List<PerformanceView> queryServiceAggregationTermsPerf(RESOURCE_TYPE type, SearchCondition searchCondition)
			throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			String[] indices = parseIndices(APP_DEFAULT, type, null, (Date) item.getValue(),
						(Date) item.getValue_End());
//			String indices[] = {"apm_tran_y2016_m6_d13"};
			String indextype = Scope.APMRUNNING_PERFS.getType();
			return queryAggregationTermsPerf(null, indices, indextype, searchCondition);
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
	}
	
	public List<PerformanceView> queryAggregationTermsTradePerf(String applicationId, String[] indices, String indextype,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();

		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndicesOptions(IndicesOptions.lenientExpandOpen());
			searchBuilder.setSize(100);
			
			searchBuilder.setIndices(indices).setTypes(indextype).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseTradeTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public PagingList<PerformanceView> queryTermsCount(SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item1 = searchCondition.getConditionItem("startTime");
		
		if (item1 == null)
			throw new IllegalArgumentException("交易跟踪查询失败,条件参数startTime不存在");
		PagingList<PerformanceView> result = new PagingList<PerformanceView>();
		try {
			QueryBuilder filter = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getTransactionIndices((Date) item1.getValue(),
					(Date) item1.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
			             .setTypes(Scope.APMRUNNING_TRANS.getType()).setQuery(filter);
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseNestedMultiTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public List<PerformanceView> queryErrorTermsPerf(String applicationId, RESOURCE_TYPE type,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			String indices[] = parseIndices(applicationId, type, null, (Date) item.getValue(),
						(Date) item.getValue_End());
			String indextype = Scope.APMRUNNING_PERFS.getType();
			if (StringUtils.isNotBlank(applicationId)) {
				searchCondition.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
			}
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndicesOptions(IndicesOptions.lenientExpandOpen());
			searchBuilder.setSize(100);
			
			searchBuilder.setIndices(indices).setTypes(indextype).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseNestedMultiTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public PagingList<PerformanceView> querySubAggregationData(SearchCondition searchCondition) throws ApmDataIndicatorException {
		StopWatch dataWatch = new StopWatch();
		dataWatch.start();
		SearchConditionItem item1 = searchCondition.getConditionItem("startTime");
		if (item1 == null)
			throw new IllegalArgumentException("交易跟踪查询失败,条件参数startTime不存在");
		PagingList<PerformanceView> result = new PagingList<PerformanceView>();
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = PerfIndicesBuilder.getInstance().getTransactionIndices((Date) item1.getValue(),
					(Date) item1.getValue_End());
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
			             .setTypes(Scope.APMRUNNING_TRANS.getType()).setQuery(queryBuilder);
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			dataWatch.split();
			log.info("最慢交易--ES--数据--001: "+dataWatch.getSplitTime());
			dataWatch.stop();
			List<Map<String, Object>> aggs = AggregationUtil.parseSubTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	@Override
	public List<PerformanceView> queryAggregationTermsPerfForApps(RESOURCE_TYPE type, SearchCondition searchCondition)
			throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("timestamp");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			String indices[] = parseIndices(null, type, null, (Date) item.getValue(),
						(Date) item.getValue_End());
			String indextype = Scope.APMRUNNING_PERFS.getType();
			return queryAggregationTermsPerf(null, indices, indextype, searchCondition);
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
	}

	
	/**
	 * 新方法从这里开始
	 */
	@Override
	public List<PerformanceView> queryAggregationTermsPerf(SearchCondition searchCondition) throws ApmDataIndicatorException {
		SearchConditionItem item = searchCondition.getConditionItem("agentStartTime");
		if (item == null)
			throw new IllegalArgumentException("统计查询失败,条件参数timestamp不存在");
		try {
			String indices[] = parseIndices(Long.valueOf(item.getValue().toString()), Long.valueOf(item.getValue_End().toString()));
			String indextype = Scope.APM_PINPOINT_SPAN.getType();
			return queryAggregationTermsPerf(indices, indextype, searchCondition);
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
	}
	
	public List<PerformanceView> queryAggregationTermsPerf(String[] indices, String indextype,
			SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		try {
			if (ArrayUtils.isEmpty(indices))
				return result;
			
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndicesOptions(IndicesOptions.lenientExpandOpen());
			searchBuilder.setSize(100);
			
			searchBuilder.setIndices(indices).setTypes(indextype).setQuery(queryBuilder);
			for (AbstractAggregationBuilder aggregation : searchCondition.getAggregations()) {
				searchBuilder.addAggregation(aggregation);
			}
			SearchResponse response = searchBuilder.execute().actionGet();
			List<Map<String, Object>> aggs = AggregationUtil.parseTermsAggregations(response.getAggregations());
			for (Map<String, Object> map : aggs) {
				result.add(new PerformanceView(map));
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}

	private String[] parseIndices(Long start, Long end) throws Exception {
		PerfIndicesBuilder perfIncidesBuilder = PerfIndicesBuilder.getInstance();
		String format = perfIncidesBuilder.PINPOINT_SPAN_Y_M_D;
		return perfIncidesBuilder.getPerfIndices(format, start, end);
	}

	@Override
	public List<PerformanceView> queryPerformanceDetail(SearchCondition searchCondition) throws ApmDataIndicatorException {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchConditionItem item = searchCondition.getConditionItem("agentStartTime");
		if (item == null)
			throw new IllegalArgumentException("错误交易查询失败,条件参数timestamp不存在");
		try {
			QueryBuilder queryBuilder = searchCondition.parseCondition();
			String indices[] = parseIndices(Long.valueOf(item.getValue().toString()), Long.valueOf(item.getValue_End().toString()));
			if (ArrayUtils.isEmpty(indices))
				return result;

			SearchRequestBuilder searchBuilder = client.prepareSearch();
			searchBuilder.setIndices(indices).setIndicesOptions(IndicesOptions.lenientExpandOpen())
					.setTypes(Scope.APM_PINPOINT_SPAN.getType()).setPostFilter(queryBuilder)
					.setFrom(searchCondition.getStartRecord()).setSize(searchCondition.getPageSize());
			if (StringUtils.isNotEmpty(searchCondition.getSortField()))
				searchBuilder.addSort(searchCondition.getSortField(),
						SortOrder.valueOf(searchCondition.getSortDirection().toUpperCase()));
			SearchResponse response = searchBuilder.execute().actionGet();
			if (response != null) {
				for (SearchHit hit : response.getHits()) {
					String source = hit.sourceAsString();
					result.add(new PerformanceView(JsonUtil.json2map(source)));
				}
			}
		} catch (Exception e) {
			throw new ApmDataIndicatorException(e);
		}
		return result;
	}
	
}